#!/usr/bin/python
# -*- coding: utf-8 -*-

''''ある単語(列)の入力に対して単語集合＋スコアを出力するモジュール'''

import re
from ..SearchEngine import YahooJapan
from .. import Util
from .TextAnalyzer import DFofSearchResult

#両方向構文パターン
class Yayala:
    '''
    注意！
    Yayalaのアルゴリズムは京都大学の大島裕明 氏の手法である。
    この関数を論文等で使用する際には以下の引用を行うこと
    -大島裕明、田中克己　両方向構文パターンを用いた検索エンジンからの高速関連語発見手法　日本データベース学会論文誌 Vol7,No.3 (2008.12)

    
    Yayalaクラスの使用例：
    y=Yayala(u"である<query>",u"(代表する|有名な)(、)?",
             u'"である<query>"',u'"である<query>" (代表する|有名な)')
    
    for word,score in y.Find(u"トヨタ").iteritems():
        print Util.JapaneseConsole(word),score
    '''
   
    def __init__(self,unicodedRegexPatternPrefix,unicodedRegexPatternPostfix,unicodedQueryPrefix,unicodedQueryPostfix):
        self.r_pre=unicodedRegexPatternPrefix
        self.r_post=unicodedRegexPatternPostfix
        self.q_pre=unicodedQueryPrefix
        self.q_post=unicodedQueryPostfix
    
    def Find(self,word,minMatch=3):
        regexPatternPrefix=self.r_pre.replace("<query>",word)
        regexPatternPostfix=self.r_post.replace("<query>",word)
        queryPrefix=self.q_pre.replace("<query>",word)
        queryPostfix=self.q_post.replace("<query>",word)
        
        yahoo=YahooJapan.WebSearchEngine()
        yahoo.JapaneseOnly=True
        yahoo.ResultCount=100
        
        scores=dict()
        for result in yahoo.Search(queryPrefix):
            for k,score in self.__regMatchPreArray(regexPatternPrefix,result.Title,2).iteritems():
                if not scores.has_key(k):
                    scores[k]=-score
                else:
                    scores[k]-=score
            for k,score in self.__regMatchPreArray(regexPatternPrefix,result.Description).iteritems():
                if not scores.has_key(k):
                    scores[k]=-score
                else:
                    scores[k]-=score

        for result in yahoo.Search(queryPostfix):
            for k,score in self.__regMatchPostArray(regexPatternPostfix,result.Title,2).iteritems():
                if not scores.has_key(k):
                    continue
                else:
                    if scores[k]<0:
                        scores[k]=-scores[k]
                    scores[k]+=score
            for k,score in self.__regMatchPostArray(regexPatternPostfix,result.Description,1).iteritems():
                if not scores.has_key(k):
                    continue
                else:
                    if scores[k]<0:
                        scores[k]=-scores[k]
                    scores[k]+=score
        
        #しきい値以下をすべて削除
        for k in scores.keys():
            if scores[k]<minMatch:
                del scores[k]
                
        return scores
    
    def __regMatchPreArray(self,regex,subject,weight=1):
        ret=dict()
        for m in re.compile(regex).finditer(subject):
            offset=m.start()
            start=max((0,offset-15))
            substr=Util.Trim(subject[start:offset],u".,;:&、。・")
            for w in (substr[s:] for s in xrange(0,len(substr))):
                if not ret.has_key(w): ret[w]=0
                ret[w]+=weight
        return ret
    
    def __regMatchPostArray(self,regex,subject,weight=1):
        ret=dict()
        for m in re.compile(regex).finditer(subject):
            offset=m.end()
            end=min((len(subject),offset+15))
            substr=Util.Trim(subject[offset:end],u".,;:&、。・")
            for w in (substr[:e+1] for e in xrange(0,len(substr))):
                if not ret.has_key(w): ret[w]=0
                ret[w]+=weight
        return ret

#Yahooの検索結果のDF        
def DFofYahooWebSearch(unicodedQuery,n=100,unicodedTermList=None,useYahoo=False):
    yahoo=YahooJapan.WebSearchEngine()
    yahoo.ResultCount=n
    return DFofSearchResult(yahoo.Search(unicodedQuery),unicodedTermList,useYahoo)
    
#YahooのBlog検索結果のDF        
def DFofYahooBlogSearch(unicodedQuery,n=100,unicodedTermList=None,useYahoo=False):
    yahoo=YahooJapan.BlogSearchEngine()
    yahoo.ResultCount=n
    return DFofSearchResult(yahoo.Search(unicodedQuery),unicodedTermList,useYahoo)
        
def FindSubject(context,obj):
    '''例：京都(=context)の嵐山(=obj)は何で有名?'''
    y=Yayala(u'(といえば|というと)<query>',u'<query>(などの|みたいな|のような|といった)',context+u' ("というと<query>" OR "といえば<query>")',context+u' ("<query>などの" OR "<query>みたいな" OR "<query>のような" OR "<query>といった")')
    return sorted(((s,c) for s,c in y.Find(obj,2).iteritems() if len(s)>=2 and s!=context),key=lambda x:x[1],reverse=True)

def FindRival(subject,obj1):
    '''例：京都 紅葉(=subject)で嵐山(=obj1)のライバルは?'''
    y=Yayala(u'(や|とか)<query>',u'<query>(や|とか)',subject+u' ("や<query>" OR "とか<query>")',subject+u' ("<query>や" OR "<query>とか")')
    return sorted(((s,c) for s,c in y.Find(obj1,7).iteritems() if len(s)>=2 and s!=subject),key=lambda x:x[1],reverse=True)

def FindInstance(context,subject):
    '''ExtractCharWordsの簡易版。
    例：京都(=context)の紅葉(=subject)といえば?
    '''
    y=Yayala(u'(の|などの|みたいな|のような|といった)<query>',u'<query>(といえば|というと|で有名な)',context+u' ("の<query>" OR "みたいな<query>" OR "のような<query>" OR "といった<query>")',context+u' ("<query>というと" OR "<query>といえば" OR "<query>で有名な")')
    return sorted(((s,c) for s,c in y.Find(subject,2).iteritems() if len(s)>=2 and s!=context),key=lambda x:x[1],reverse=True)
    

def ExtractCharWords(q,subject,printRival=False,forceUseYahoo=False):
    '''例：京都(=q)の紅葉名所(=subject)といえば?'''
    res=FindRival(subject,q)
    
    q2=None if len(res)==0 else res[0][0]
    useYahoo=(forceUseYahoo or (not q2 is None)) 
    
    if printRival: print u'%s::%s<=>"%s"' %(subject,q,q2)
    
    tflist0=DFofYahooWebSearch(q+" "+subject,200,None,useYahoo).iteritems()
    tflist1=[[t,cnt] for t,cnt in tflist0 if cnt>8 and len(t)>=2 and (not q in t) and (not subject in t)]
    keys=[t for t,s in tflist1]
    for i in xrange(1,len(keys)):
        for j in xrange(i):
            if keys[i] in keys[j]:
                tflist1[j][1]+=tflist1[i][1]/2
                tflist1[i][1]=0
    tflist2=[(l[0],l[1]) for l in tflist1 if l[1]>10]
    tflist2.sort(key=lambda x:x[1],reverse=True)
    
    termlist=[t for t,cnt in tflist2 if DFofYahooWebSearch(subject+" "+t,5,(q,))[q]>0]
    
    if not q2 is None:
        rtflist0=DFofYahooWebSearch(q2+" "+subject, 5,termlist)
        termlist=(t for t in termlist if (not rtflist0.has_key(t)) or rtflist0[t]==0)
        def okey(df):
            return df[q]>df[q2]
        termlist=(t for t in termlist if DFofYahooWebSearch(q+" "+t,50,(subject,))[subject]>0)
        termlist=[t for t in termlist if okey(DFofYahooWebSearch(subject+" "+t,50,(q,q2)))]
    
    return termlist

#共起頻度の差
def CoOccurentTermExtractor(unicodedTerm1,unicodedTerm2,n1=200,n2=150,p=0.05,s1=2,s2=2,UseYahoo=False):
    '''
    2つの入力（AとB）について、
    A+Bではよく現れるが
    A+not(B)やnot(A)+Bでは現れない単語を探す

    #使用例
    from yi01lib.LangProcess import TermExtractor
    from yi01lib.Util import PrintDict
    
    PrintDict(TermExtractor.CoOccurentTermExtractor(u"潮岬",u"観光"))
    
    '''
    #A+B
    df=DFofYahooWebSearch(unicodedTerm1+u" "+unicodedTerm2,n1,useYahoo=UseYahoo)
    #しきい値以下は切る
    for k in df.keys():
        if df[k]<=n1*p:
            del df[k]
    
    #not(A)+B
    for k,v in DFofYahooWebSearch(u"-"+Util.Trim(unicodedTerm1)+u" "+unicodedTerm2,n2,df.keys()).iteritems():
        if not df.has_key(k): continue
        #しきい値以下は切る
        if df[k]<=v*s1*n1/n2:
            del df[k]

    #A+not(B)
    for k,v in DFofYahooWebSearch(unicodedTerm1+u" -"+Util.Trim(unicodedTerm2),n2,df.keys()).iteritems():
        if not df.has_key(k): continue
        #しきい値以下は切る
        if df[k]<=v*s2*n1/n2:
            del df[k]

    def deleteIfSimilar(d,k1,k2):
        if not d.has_key(k1): return
        if not d.has_key(k2): return
        
        if k1 in k2:
            del d[k1]
        elif k2 in k1:
            del d[k2]

    keys=df.keys()
    for i1 in xrange(0,len(keys)-1):
        for i2 in xrange(i1+1,len(keys)):
            deleteIfSimilar(df,keys[i1],keys[i2])
    return df
